require 'ServerPilot/version'
require 'rest-client'
require 'uri'
require 'json'
require 'ostruct'

module ServerPilot
  # Class to access the serverpilot api
  class API
    attr_accessor :scheme
    attr_accessor :host
    attr_accessor :port
    attr_accessor :client_id
    attr_accessor :secret_key

    def initialize(api_client, api_key)
      @client_id = api_client
      @secret_key = api_key
      @scheme = 'https'
      @host = 'api.serverpilot.io'
      @port = 443
    end

    def build_path(action, id = nil)
      if action == 'ssl'
        ['/v1', 'apps', id, 'ssl'].join('/') unless id.nil?
      else
        (id.nil?) ? ['/v1', action].join('/') : ['/v1', action, id].join('/')
      end
    end

    def check_function_name_valid(name)
      (name.to_s.include? '_') && (name.to_s.count('_') == 1) ? true : false
    end

    def get_function_verb(name)
      case name.to_s.downcase
      when /^get/ then 'get'
      when /^post/ then 'post'
      when /^delete/ then 'delete'
      end
    end

    def get_params(arguments)
      params = nil
      arguments.each do |argument|
        params = argument if argument.is_a?(Hash)
      end
      params
    end

    def get_action_name(name)
      name.to_s.downcase.split('_').last
    end

    def get_path(arguments, action)
      if arguments.length == 0
        build_path(action)
      else
        if arguments[0].is_a?(Integer) || arguments[0].is_a?(String)
          build_path(action, arguments[0])
        else
          build_path(action)
        end
      end
    end

    def create_uri(path)
      URI::Generic.build(
        scheme: @scheme,
        host: @host,
        path: path,
        port: @port
      ).to_s
    end

    def create_rest_client(verb, path, params = nil)
      if params
        RestClient::Request.new(
          method: verb,
          url: create_uri(path),
          user: @client_id,
          password: @secret_key,
          headers: { 'Content-Type' => 'application/json' },
          payload: params.to_json
        )
      else
        RestClient::Request.new(
          method: verb,
          url: create_uri(path),
          user: @client_id,
          password: @secret_key
        )
      end
    end

    def execute_api_command(verb, path, params = nil)
      client = create_rest_client verb, path, params
      client.execute
    end

    def parse_json(response)
      body = JSON.parse(response.to_str) if response.code == 200
      OpenStruct.new(code: response.code, body: body)
    end

    def execute_request(verb, name, arguments)
      parse_json(
        execute_api_command(
          verb,
          get_path(arguments, get_action_name(name)),
          get_params(arguments)
        )
      )
    end

    def method_missing(name, *arguments)
      if check_function_name_valid name
        verb = get_function_verb name
        if verb
          execute_request verb, name, arguments
        else
          fail 'Invalid verb (get, post or delete supported)'
        end
      else
        fail 'Invalid function name'
      end
    end
  end
end
